package com.kehutong.charge.job;

import com.coraframework.quartz.Job;
import com.coraframework.quartz.JobExecutionContext;
import com.coraframework.quartz.JobExecutionException;
import com.kehutong.charge.entity.ChargeBillConfig;
import com.kehutong.charge.entity.ChargeBillHouse;
import com.kehutong.charge.entity.ChargeBillItems;
import com.kehutong.charge.service.CommonService;
import com.kehutong.charge.util.CommonClient;
import com.kehutong.charge.util.CommonUtil;
import com.kehutong.charge.util.enums.ChargeBillStatusEnum;
import com.kehutong.charge.util.enums.ChargeLogEnum;
import com.kehutong.common.DoveClient;
import com.kehutong.common.Java8TimeUtils;
import com.kehutong.common.dto.UniformSendReqDto;
import com.kehutong.common.enums.MessageBusinessEnum;
import com.kehutong.common.enums.TemplateType;
import com.kehutong.common.util.BigDecimalUtils;
import com.kehutong.common.util.DateUtil;
import com.kehutong.common.util.TemplateReplaceUtil;
import org.coraframework.json.JSONArray;
import org.coraframework.json.JSONObject;
import org.coraframework.logger.Logger;
import org.coraframework.logger.LoggerFactory;
import org.coraframework.orm.Pool;
import org.coraframework.orm.jdbc.JdbcSession;
import org.coraframework.orm.jdbc.connection.ThreadLocalCache;
import org.coraframework.util.Ioc;
import org.coraframework.util.Objects;

import java.math.BigDecimal;
import java.util.*;

/**
 * 房屋账单定时任务
 *
 * @author wupengfei
 */
public class ChargeBillHouseJob implements Job {

    private static final Logger logger = LoggerFactory.getLogger(ChargeBillHouseJob.class);

    public ChargeBillHouseJob() {
    }

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        try {
            logger.info("房屋账单定时任务开始！");
            Map<String, Integer> corpMap = generateHouseBill(null);
            logger.info("执行结果corpMap=" + corpMap);
        } catch (Exception e) {
            logger.error("房屋账单定时任务执行时异常！", e);
        }
    }

    public static Map<String, Integer> generateHouseBill(String billDate) {
        JdbcSession jdbcSession = Ioc.getInstance(JdbcSession.class);
        CommonService commonService = Ioc.getInstance(CommonService.class);
        CommonClient commonClient = Ioc.getInstance(CommonClient.class);
        DoveClient doveClient = Ioc.getInstance(DoveClient.class);

        // 查询今天出账的账单
        Map<String, Integer> result = new HashMap<>();
        if (Objects.isBlank(billDate)) {
            billDate = DateUtil.format(new Date(), "yyyy-MM-dd");
        }
        billDate += " 00:00:00";
        List<ChargeBillConfig> billConfigList = jdbcSession.findArray(ChargeBillConfig.class).eq("billDate", billDate).exe();
        for (ChargeBillConfig each : billConfigList) {
            int size = doGenerateHouseBill(jdbcSession, commonService, commonClient, doveClient, each);
            result.put(each.getCorpId(), size);
        }
        return result;
    }

    private static int doGenerateHouseBill(JdbcSession jdbcSession, CommonService commonService, CommonClient commonClient, DoveClient doveClient, ChargeBillConfig chargeBillConfig) {
        try {
            logger.info("生成账单corpId=" + chargeBillConfig.getCorpId());
            ThreadLocalCache.current().setCorpId(chargeBillConfig.getCorpId());
            // 查询待缴费的账单
            List<ChargeBillItems> billItems = jdbcSession.findArray(ChargeBillItems.class)
                    .eq("deleted", false)
                    .eq("communityNo", chargeBillConfig.getCommunityNo())
                    .eq("billDate", chargeBillConfig.getBillDate())
                    .eq("billYearMonth", chargeBillConfig.getBillYearMonth())
                    .eq("billStatus", ChargeBillStatusEnum.BILL_WAIT_PAID)
                    .exe();

            // 按房屋和缴费人分组
            Map<String, Map<String, List<ChargeBillItems>>> houseBillItemsMap = new HashMap<>();
            for (ChargeBillItems each : billItems) {
                Map<String, List<ChargeBillItems>> chargeBillItemsMap = houseBillItemsMap.computeIfAbsent(each.getHouseNo(), k -> new HashMap<>());
                List<ChargeBillItems> billItemsList = chargeBillItemsMap.computeIfAbsent(each.getUserNo(), k -> new ArrayList<>());
                billItemsList.add(each);
            }

            for (Map.Entry<String, Map<String, List<ChargeBillItems>>> entry : houseBillItemsMap.entrySet()) {
                String houseNo = entry.getKey();
                for (Map.Entry<String, List<ChargeBillItems>> chargeEntry : entry.getValue().entrySet()) {
                    String userNo = chargeEntry.getKey();
                    List<ChargeBillItems> billItemsList = chargeEntry.getValue();

                    // 校验此房屋和缴费人是否已生成账单
                    List<ChargeBillHouse> houseBillList = jdbcSession.findArray(ChargeBillHouse.class)
                            .eq("deleted", false)
                            .eq("houseNo", houseNo)
                            .eq("userNo", userNo)
                            .noEq("billStatus", ChargeBillStatusEnum.BILL_PAID_CLOSE.getId())
                            .eq("billYearMonth", chargeBillConfig.getBillYearMonth())
                            .exe();
                    boolean isHasHouse = false;
                    for (ChargeBillHouse eachHouse : houseBillList) {
                        if (eachHouse.getBillStatus() == ChargeBillStatusEnum.BILL_PAID_FINISH || eachHouse.getBillStatus() == ChargeBillStatusEnum.BILL_WAIT_PAID) {
                            isHasHouse = true;
                            break;
                        }
                    }
                    if (isHasHouse) {
                        logger.info("房屋已有账单houseNo" + houseNo + ",userNo=" + userNo + ",billYearMonth=" + chargeBillConfig.getBillYearMonth());
                        continue;
                    }

                    // 生成房屋账单
                    ChargeBillHouse chargeBillHouse = generateHouseBill(commonService, billItemsList);
                    jdbcSession.insert(chargeBillHouse);
                    jdbcSession.updateById(billItemsList);

                    // 发送通知
                    for (ChargeBillItems each : billItemsList) {
                        try {
                            //根据用户查询手机号码
                            JSONObject object = commonClient.findResidentInfo(userNo);

                            //切换公司
                            List<String> phoneList = new ArrayList<>();
                            phoneList.add(object.getString("mobile")); //手机号
                            msgUniformSend(doveClient, each, userNo, TemplateType.PAY_C_MONTH_BILL_DATE, phoneList, true, chargeBillConfig.getCorpId());
                        } catch (Exception e) {
                            logger.error("发送通知时异常", e);
                        }
                    }
                }
            }
            return billItems.size();
        } catch (Exception e) {
            logger.error("生成账单时异常");
            return 0;
        }
    }

    private static ChargeBillHouse generateHouseBill(CommonService commonService, List<ChargeBillItems> billItemsList) {
        //生成账单
        ChargeBillHouse chargeBillHouse = Pool.newInstance(ChargeBillHouse.class);
        chargeBillHouse.setHouseBillNo(CommonUtil.generateRandom("FW"));

        // 计算金额
        BigDecimal amountHouse = new BigDecimal(0);
        for (ChargeBillItems each : billItemsList) {
            amountHouse = BigDecimalUtils.add(amountHouse, each.getBillAmount(), 2);
            each.setHouseBillNo(chargeBillHouse.getHouseBillNo());
        }

        ChargeBillItems chargeBillItems = billItemsList.get(0);
        chargeBillHouse.setChargeName(chargeBillItems.getChargeName());
        chargeBillHouse.setResidentsType(chargeBillItems.getResidentsType());
        chargeBillHouse.setBillYearMonth(chargeBillItems.getBillYearMonth());
        chargeBillHouse.setUserNo(chargeBillItems.getUserNo());
        chargeBillHouse.setHouseNo(chargeBillItems.getHouseNo());

        chargeBillHouse.setBillAddress(chargeBillItems.getBillAddress());
        chargeBillHouse.setBuildNo(chargeBillItems.getBuildNo());
        chargeBillHouse.setBuildName(chargeBillItems.getBuildName());
        chargeBillHouse.setCommunityName(chargeBillItems.getCommunityName());
        chargeBillHouse.setMergeName(chargeBillItems.getMergeName());
        chargeBillHouse.setBillAmount(amountHouse);
        chargeBillHouse.setBillAmountUnPaid(amountHouse);

        chargeBillHouse.setCommunityNo(chargeBillItems.getCommunityNo());
        chargeBillHouse.setCommunityBillNo(chargeBillItems.getCommunityBillNo());
        chargeBillHouse.setBillStatus(ChargeBillStatusEnum.BILL_WAIT_PAID);
        chargeBillHouse.setChargeStatus(ChargeBillStatusEnum.BILL_UN_PAID);
        chargeBillHouse.setBillCycleStart(chargeBillItems.getBillCycleStart());
        chargeBillHouse.setBillCycleEnd(chargeBillItems.getBillCycleEnd());
        chargeBillHouse.setBillDate(chargeBillItems.getBillDate());
        chargeBillHouse.setChargeDate(chargeBillItems.getChargeDate());
        chargeBillHouse.setPenaltyDate(chargeBillItems.getPenaltyDate());

        //计算违约天数,生成账单没有违约
        chargeBillHouse.setPenaltyDays(Java8TimeUtils.subDate(chargeBillItems.getPenaltyDate()));
        chargeBillHouse.setPenaltyAmount(new BigDecimal(0));
        chargeBillHouse.setDepartmentNo(chargeBillItems.getDepartmentNo());
        chargeBillHouse.setDepartmentName(chargeBillItems.getDepartmentName());
        chargeBillHouse.setDepartmentNos(chargeBillItems.getDepartmentNos());
        chargeBillHouse.setCreateName(chargeBillItems.getCreateName());

        commonService.insetLogger(chargeBillHouse.getHouseBillNo(),
                ChargeLogEnum.LOG_CHARGE_BILL_COM.getDesc(),
                "创建常规账单",
                ChargeBillStatusEnum.BILL_WAIT_PAID.getDesc(),
                ChargeBillStatusEnum.BILL_UN_PAID.getDesc(), "操作成功", chargeBillItems.getCreateName());
        return chargeBillHouse;
    }

    /**
     * 发送消息
     *
     * @param manage       模板替换内容对象
     * @param uuid         用户ID
     * @param templateType 模板CODE
     * @param phoneList    手机号
     * @param userCreate   是否小程序用户，false 员工，true 小程序用户
     * @throws Exception
     */
    private static void msgUniformSend(DoveClient doveClient, ChargeBillItems manage, String uuid, TemplateType templateType, List<String> phoneList, boolean userCreate, String companyNo) throws Exception {
        // 获取消息推送配置文件
        JSONObject configJson = doveClient.post("/crm/message/global/config/service/get", (http) -> {
            http.addParam("templateType", templateType.getId());
        });

        if (configJson.getIntValue("code") == 200) {
            UniformSendReqDto dto = getUniformSendReqDto(doveClient, manage, uuid, templateType, phoneList, configJson.getJSONObject("data"), userCreate, companyNo);
            // 消息推送
            doveClient.post("/crm/message/service/uniformSend", (http) -> {
                http.addParam("temp", JSONObject.toJSONString(dto));
            });
        }
    }

    private static UniformSendReqDto getUniformSendReqDto(DoveClient doveClient, ChargeBillItems manage, String uuid, TemplateType templateType,
                                                          List<String> phoneList, JSONObject dataJson, boolean userCreate,
                                                          String companyNo) throws Exception {
        UniformSendReqDto dto = new UniformSendReqDto();
        dto.setMsgId(manage.getId());
        dto.setBusinessTypeId(MessageBusinessEnum.MSG_BILL_PAY.getId());
        dto.setTemplateTypeId(templateType.getId());
        dto.setCompanyNo(companyNo);
        dto.setUserCreate(userCreate);
        dto.setUuid(uuid);
        dto.setTitle("缴费提醒");

        JSONObject inner = dataJson.getJSONObject("messageTemplateInner");
        if (dataJson.getBooleanValue("innerSend") && org.coraframework.util.Objects.nonNull(inner)) {
            dto.setTitle(inner.getString("title"));
            dto.setInnerData(TemplateReplaceUtil.replace(inner.getString("content"), inner.getString("tagArray"), manage));
            dto.setPageParam(String.format("companyNo=%s&houseNo=%s", companyNo, manage.getHouseNo()));
        }

        JSONObject sms = dataJson.getJSONObject("messageTemplateSms");
        if (dataJson.getBooleanValue("smsSend") && org.coraframework.util.Objects.nonNull(sms)) {
            if (org.coraframework.util.Objects.nonEmpty(phoneList)) {
                dto.setPhoneList(phoneList);
                dto.setSmsDataParams(TemplateReplaceUtil.listTencentSmsParam(sms.getString("content"), sms.getString("tagArray"), manage));
            } else {
                JSONObject jsonObject = doveClient.post("/kht-bin/auth/user/listPhone", http -> {
                    JSONObject temp = new JSONObject();
                    temp.put("id", Arrays.asList(uuid));
                    http.setBody(temp.toJSONString());
                });
                List<String> listPhone = JSONArray.parseArray(jsonObject.getString("data"), String.class);
                if (org.coraframework.util.Objects.nonEmpty(listPhone)) {
                    dto.setPhoneList(listPhone);
                    dto.setSmsDataParams(TemplateReplaceUtil.listTencentSmsParam(sms.getString("content"), sms.getString("tagArray"), manage));
                }
            }
        }

        String wxchatTemplate = dataJson.getString("wxchatTemplate");
        if (dataJson.getBooleanValue("wxchatSend") && org.coraframework.util.Objects.nonNull(wxchatTemplate)) {
            dto.setWxChatData(getWxchatTemplate(templateType, manage));
            dto.setPageParam(String.format("companyNo=%s&houseNo=%s", companyNo, manage.getHouseNo()));
        }

        return dto;
    }

    private static String getWxchatTemplate(TemplateType templateType, ChargeBillItems manage) {
        JSONObject data = new JSONObject();

        if (TemplateType.PAY_C_MONTH_BILL_DATE == templateType) {

            data.put("first", buildMpMessageData("您的月度账单已生成"));
            // 房号
            data.put("keyword1", buildMpMessageData(manage.getBillAddress()));
            // 账单年月
            data.put("keyword2", buildMpMessageData(manage.getBillYearMonth()));
            // 账单金额
            data.put("keyword3", buildMpMessageData(BigDecimalUtils.format(manage.getBillAmount()).toPlainString()));

            data.put("remark", buildMpMessageData("感谢您的关注和支持！如有疑问，请咨询物业管理处"));
            return data.toJSONString();
        } else {
            return null;
        }
    }

    private static JSONObject buildMpMessageData(String value) {
        JSONObject json = new JSONObject();
        json.put("value", value);
        return json;
    }

}
